package cate.game.server.configuration;

import cate.common.rpc.RpcReg4Game;
import cate.game.GameBody;
import cate.game.ManyGame;
import cate.game.activity.base.ActivityLoader;
import cate.game.client.interceptor.*;
import cate.game.common.rpc.RpcListener4Game;
import cate.game.common.rpc.RpcListener4Process;
import cate.game.common.rpc.RpcSender4Game;
import cate.game.common.scanner.GameScanner;
import cate.game.event.GameEventDispatcher;
import cate.game.event.GameEventDispatcherImpl;
import cate.game.framework.GameConfig;
import cate.game.framework.GameFacilities;
import cate.game.framework.share.Shared;
import cate.game.server.GameServerApplication;
import cate.game.server.configuration.part.GameSqliteImpl;
import cate.game.server.rpc.*;
import cate.game.server.configuration.part.CommandExecutorBuilder;
import cate.game.server.rpc.fax.FaxGameUtils;
import cate.game.server.service.CheckService;
import cate.game.server.service.MailService;
import cate.game.table.TableManager;
import cate.game.util.GameTools;
import cp.bi.CpBiClient;
import cp.game.framework.*;
import cp.server.template.gs.util.LogcatImpl;
import cp.server.template.gs.util.ProgramInfo;
import cp.solution.business.game.boot.GameSrvBootstrap;
import cp.solution.business.gm.KfRebateConf;
import cp.solution.business.sys.env.EnvironmentVarSets;
import cp.solution.fax.FaxTags;
import cp.solution.rpc.RpcReg4Solution;
import cp.solution.rpc.RpcSender;
import cp.solution.rpc.bridge.FaxRpcSender;
import cp.solution.rpc.codec.part.ComboCodecConfiguration;
import cp.solution.rpc.template.RpcSenderTemplate;
import fax.client.FaxClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.*;

@Slf4j
@Configuration
public class InitConfig {

    @Bean
    public ManyGameConfig getManyGameConfig(GameServerEnv env, DebugGlobalConf debugConf) {
        debugConf.check();
        new ComboCodecConfiguration()
                .handle(RpcReg4Solution::handle)
                .handle(RpcReg4Game::handle)
                .buildAndUseCodec();
        return env.buildConfig();
    }

    @Bean
    public ApiCaller getApiCaller(ManyGameConfig manyGameConfig) {
        return manyGameConfig.buildApiCaller();
    }

    @Bean
    public ConfigFromConsole getConfigFromConsole(ApiCaller apiCaller) {
        ConfigFromConsole cfc = apiCaller.buildConfigFromConsole();
        EnvironmentVarSets.getInstance().readWith(apiCaller.pc());
        return cfc;
    }

    @Bean
    public Map<Integer, GameSrvBootstrap> gameSrvBootstraps(ConfigFromConsole configFromConsole) {
        return configFromConsole.buildGameSrvBootstrapMap();
    }

    @Bean
    public IProgramInfo getProgramInfo(ProjectInfoAutoConfiguration projectInfoAutoConfiguration) {
        return new ProgramInfo().read(projectInfoAutoConfiguration);
    }

    @Bean
    ILogcat getLogcat() {
        return new LogcatImpl();
    }

    @Bean FaxClientHandler getFaxClientHandler() {
        return new FaxClientHandler();
    }

    @Bean
    public FaxClient getFaxClient(ConfigFromConsole configFromConsole, FaxClientHandler faxClientHandler) throws Exception {
        return FaxGameUtils.buildFaxClient(configFromConsole, faxClientHandler);
    }


    @Bean
    public RpcSenderTemplate getRpcSenderTemplate(FaxClient faxClient, DebugGlobalConf debugConf) {
        RpcSender _sender = new FaxRpcSender(faxClient);
        if(debugConf.debugShareService) {
            _sender.setMsgHeadHandler(msgHead -> msgHead.addTag(FaxTags.TAG_DEV_MODE, FaxTags.DEV_MODE_DEBUG));
        }
        //
        RpcSenderTemplate template = new RpcSenderTemplate();
        template.sender(_sender);
        return template;
    }

    @Bean
    public RpcListener4Process getRpcListener4Process(FaxClientHandler faxClientHandler) {
        RpcListener4Process processHandler = new RpcListener4ProcessImpl();
        faxClientHandler.regForProcess(processHandler);
        return processHandler;
    }

    @Bean
    public ManyGame manyGame(DebugGlobalConf debugConf, ManyGameConfig config,
                             ApiCaller apiCaller,
                             ConfigFromConsole configFromConsole,
                             IProgramInfo programInfo,
                             ILogcat logcat,
                             FaxClientHandler faxClientHandler,
                             RpcSenderTemplate rpcSender,
                             MailService mailService,
                             CheckService checkService,
                             Map<Integer, GameSrvBootstrap> gsbMap, ApplicationContext ctx) throws Exception {
        log.info("ctx={}", ctx);
        GameServerApplication.ctx = ctx;
        ManyGame games = new ManyGame(config, configFromConsole, apiCaller, programInfo, logcat);
        if(!debugConf.debugExcelLoadDisabled) {
            if (!TableManager.instance.setup(config.excelPath, configFromConsole.excelMode)) {
                GameServerApplication.shutdownForce("读取excel表，有大于50%的表不存在，可能是配错excel路径了");
            }
            // 初始化物品文档
//            ItemConfigHelper.instance.init(config.excelPath);
        } else {
            log.warn("因为debugExcelLoadDisabled，所以跳过了Excel的加载");
        }
        if(!debugConf.debugFastStartup) {
            ActivityLoader.getInstance().load("cate.game.activity");
        }

        GameTools tools = new GameTools();
        tools.setup(games);

        final GameEventDispatcher dispatcher = new GameEventDispatcherImpl();
        final CommandExecutor commandExecutor = CommandExecutorBuilder.build();
        boolean lazyThreadStart = false;
        for (int srvId : configFromConsole.srvIds) {
            GameSrvBootstrap bootstrap = gsbMap.get(srvId);
            log.info("游戏主体被实例化 srvId={}", srvId);
            GameConfig gConf = new GameConfig();
            gConf.setup(config);
            gConf.srvId = srvId;
            gConf.gs = bootstrap.getGs();
            gConf.setUpEatenSrvIds();
            gConf.cs = bootstrap.getCs();
            gConf.mongo = bootstrap.getMongo();
            gConf.redirect = bootstrap.getRedirect();

            GameBody g = new GameBody(true);
            g.config = gConf;
            g.table = TableManager.instance;
            g.tools = tools;
            g.eventDispatcher = dispatcher;
            g.commandExecutor = commandExecutor;
            g.mail.setup(mailService);

            GameFacilities facilities = new GameFacilitiesImpl(g);
            g.facilities = facilities;
            facilities.setApi(apiCaller);

            RpcListener4Game rpcListener4Game = new RpcListener4GameImpl(gConf.gs);
            faxClientHandler.regForGame(rpcListener4Game);
            facilities.setRpcListener(rpcListener4Game);
            RpcSender4Game rpcSender4Game = new RpcSender4Game(g, rpcSender);
            facilities.setRpcSender(rpcSender4Game);

            facilities.setBi(new CpBiClient(rpcSender));
            facilities.setSqlite(new GameSqliteImpl().setup(gConf.srvId));

            //如果开服时间没有配置或者未到开服时间
            boolean lazy = bootstrap.getGs().getOpenTime() == null
                    || System.currentTimeMillis() < bootstrap.getGs().getOpenTime().getTime();
            if (lazy) {
                lazyThreadStart = true;
            }
            games.put(srvId, g);
            g.init(lazy);
        }
        GameScanner.scan();
        if (lazyThreadStart) {
            games.lazyThreadStart();
        }
        games.initGameScheduleExecutors(configFromConsole.srvIds);
        //
        mailService.setup(games);
        checkService.execute(games, TableManager.instance, tools);
        Shared.setup(games);
        return games;
    }

}
